package com.bolt.support.spring.jpa.jpql;

import com.bolt.common.utils.StrUtil;
import com.bolt.support.query.conditions.domain.SqlClause;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class OperationClause implements SqlClause<String> {

    private final Ops operator;

    private final List <SqlClause <?>> args;

    protected final static Templates templates = new Templates();

    public OperationClause(Ops operator, SqlClause <?>... arg) {
        this.operator = operator;
        args = new ArrayList <>(Arrays.asList(arg));
    }

    public OperationClause(Ops operator, List <SqlClause <?>> arg) {
        this.operator = operator;
        args = arg;
    }

    public Ops getOperator() {
        return operator;
    }


    public List <SqlClause <?>> getArgs() {
        return args;
    }

    public String toClause(Ops operator, List <? extends SqlClause <?>> clauses) {
        StringBuffer to = new StringBuffer(60);
        String pattern = templates.get(operator);
        if (operator == Ops.OR) {
            to.append("(");
        }
        for (int i = 0; i < clauses.size(); i++) {

            SqlClause <?> sqlClause = clauses.get(i);
            if (sqlClause instanceof OperationClause) {
                OperationClause operationClause = (OperationClause) sqlClause;
                // pattern = templates.get(operationClause.getOperator());
                List <? extends SqlClause <?>> subItem = templates.convert(operationClause.getOperator(), operationClause.getArgs());
                String subClauses = toClause(operationClause.getOperator(), subItem);
                to.append(subClauses);
                if ((operator == Ops.AND || operator == Ops.OR)) {
                    to.append(templates.get(operator));
                }
            } else {
                String[] arg = clauses.stream().map(k -> k.render(false)).toArray(String[]::new);
                String strSql = StrUtil.indexedFormat(pattern, arg);
                to.append(strSql);
                break;
            }

        }
        String sql = StrUtil.removeSuffix(to.toString(), templates.get(operator));
        if (operator == Ops.OR) {
            sql = sql + ")";
        }
        return sql;
    }


    @Override
    public String render(boolean addAlias) {
        StringBuffer to = new StringBuffer(60);
        this.args.stream().sorted();
        String sql = toClause(this.operator, this.args);
        to.append(sql);
        return to.toString();
    }

}

 